package cn.wps.solution.demo.repository;

import cn.wps.solution.demo.entity.FileId;
import cn.wps.solution.demo.util.FileUtils;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

@Component
@NoArgsConstructor
public class StorageRepository {

    private static final Path dir;
    private static final ConcurrentHashMap<String, Path> keys;

    static {
        try {
            dir = Files.createTempDirectory("tmp");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                try (Stream<Path> files = Files.walk(dir)) {
                    files.sorted(Comparator.reverseOrder()).forEach(FileUtils::delete);
                    System.out.println("delete tmp dir succeed");
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });

        keys = new ConcurrentHashMap<>(32);
    }

    private String key(FileId fileId) {
        return String.format("%s-%s", fileId.getId(), fileId.getVersion());
    }

    @SneakyThrows
    public void save(FileId fileId, byte[] content) {
        Objects.requireNonNull(fileId);
        Objects.requireNonNull(content);

        final String key = key(fileId);

        final Path path = Files.createTempFile(dir, key, "");
        Files.deleteIfExists(path);
        Files.write(path, content);

        keys.put(key, path);
    }

    public byte[] findByFileId(FileId fileId) {
        return Optional.ofNullable(keys.get(key(fileId))).map(FileUtils::readAllBytes).orElseThrow();
    }

    public Map<String, Path> findAll() {
        final Map<String, Path> map = new HashMap<>(keys.size());
        map.putAll(keys);
        return map;
    }
}
